package com.ben.utils.concurrent;

import android.os.Handler;
import android.os.Looper;

import com.ben.utils.log.Logger;

import java.util.concurrent.atomic.AtomicInteger;

public abstract class RunnableWrapper implements Runnable {

    private static final String TAG = RunnableWrapper.class.getSimpleName() + ".RunnableWrapper";
    private static final AtomicInteger NAME_NUMBER = new AtomicInteger(1);
    private Handler uiHandler = new Handler(Looper.getMainLooper());

    public RunnableWrapper() {

    }

    public String name() {
        return String.valueOf(NAME_NUMBER.getAndIncrement());
    }

    public int priority() {
        return Thread.NORM_PRIORITY;
    }

    public void beforeExecute() {
        Logger.i(TAG, "Thread:" + name() + " beforeExecute.");
    }

    public abstract void execute() throws Throwable;

    public void afterExecute() {
        Logger.i(TAG, "Thread:" + name() + " afterExecute.");
    }

    public void onSuccess(long consumeTime) {
        Logger.i(TAG, "Thread:" + name() + " exec success. Consume time is " + consumeTime + "ms");
    }

    public void onFail(Throwable t) {
        Logger.i(TAG, "Thread:" + name() + " exec fail.");
    }

    @Override
    public final void run() {
        String oldName = Thread.currentThread().getName();
        String name = name();
        Thread t = Thread.currentThread();
        if (name != null && !name.isEmpty()) {
            t.setName(name);
        }
        t.setPriority(priority());
        beforeExecute();
        try {
            long startTime = System.currentTimeMillis();
            Logger.i(TAG, "Thread:" + name() + " execute.");
            execute();
            long consume = System.currentTimeMillis() - startTime;
            uiHandler.post(() -> onSuccess(consume));
        } catch (InterruptedException ignore) {
            // ignore.
        } catch (final Throwable throwable) {
            uiHandler.post(() -> onFail(throwable));
        } finally {
            Thread.currentThread().setName(oldName);
        }
        afterExecute();
    }
}
